1 module d_tree_sitter.tree; 2 3 extern (C): 4 5 import d_tree_sitter.language; 6 import d_tree_sitter.node; 7 import d_tree_sitter.tree_visitor; 8 import d_tree_sitter.other; 9 import d_tree_sitter.libc : TSTree; 10 11 /** A tree that represents the syntactic structure of a source code file. */ 12 struct Tree 13 { 14 import d_tree_sitter.libc : ts_tree_delete, ts_tree_root_node, ts_tree_language, 15 ts_tree_edit, ts_tree_get_changed_ranges, ts_tree_copy, ts_tree_print_dot_graph; 16 17 import std.stdio : File; 18 19 /** internal TsTree */ 20 TSTree* tstree; 21 22 /** Create a new Tree */ 23 this(TSTree* tstree) @nogc nothrow 24 { 25 assert(tstree != null, "The given tstree is null"); 26 this.tstree = tstree; 27 } 28 29 ~this() @nogc nothrow 30 { 31 ts_tree_delete(this.tstree); 32 } 33 34 /** 35 * Create a shallow copy of the syntax tree. This is very fast. 36 * 37 * You need to copy a syntax tree in order to use it on more than one thread at 38 * a time, as syntax trees are not thread safe. 39 */ 40 this(ref return scope Tree otherTree) @nogc nothrow 41 { 42 this.tstree = ts_tree_copy(otherTree.tstree); 43 } 44 45 /// ditto 46 this(ref return scope inout Tree otherTree) @nogc nothrow inout 47 { 48 this.tstree = cast(inout(TSTree*)) ts_tree_copy(otherTree.tstree); 49 } 50 51 @disable this(this); // disable postblit 52 53 /** Create an empty Tree */ 54 static auto create_empty() @nogc nothrow 55 { 56 return cast(const(TSTree)*) null; 57 } 58 59 /** Get the root node of the syntax tree. */ 60 auto root_node() const @nogc nothrow 61 { 62 return Node(ts_tree_root_node(tstree)); 63 } 64 65 /** Get the language that was used to parse the syntax tree. */ 66 auto language() const @nogc nothrow 67 { 68 return Language(ts_tree_language(tstree)); 69 } 70 71 /** Edit the syntax tree to keep it in sync with source code that has been 72 edited. 73 74 You must describe the edit both in terms of byte offsets and in terms of 75 row/column coordinates. 76 */ 77 auto edit(const InputEdit* edit) @nogc nothrow 78 { 79 return ts_tree_edit(tstree, edit); 80 } 81 82 /** Create a new [TreeCursor] starting from the root of the tree. */ 83 auto walk() const @nogc nothrow 84 { 85 return root_node().walk(); 86 } 87 88 /** 89 Traverse the [Tree] starting from its root [Node] applying a visitor at all nodes. 90 */ 91 void traverse(TreeVisitor visitor) const 92 { 93 root_node().traverse(visitor); 94 } 95 96 /** 97 Traverse the [Tree] starting from its root [Node] applying a visitor at all nodes. 98 99 NOTE: if you are sure that TreeVisitor is nothrow, you can use this method 100 */ 101 void traverse_nothrow(TreeVisitor visitor) const 102 { 103 root_node().traverse_nothrow(visitor); 104 } 105 106 /** Compare this old edited syntax tree to a new syntax tree representing the same 107 document, returning a sequence of ranges whose syntactic structure has changed. 108 109 For this to work correctly, this syntax tree must have been edited such that its 110 ranges match up to the new tree. Generally, youl want to call this method right 111 after calling one of the [Parser::parse] functions. Call it on the old tree that 112 was passed to parse, and pass the new tree that was returned from `parse`. 113 */ 114 auto changed_ranges(Tree other) const nothrow 115 { 116 auto count = 0u; 117 const auto ptr = ts_tree_get_changed_ranges(tstree, other.tstree, &count); 118 // TODO ptr is not freed! 119 // TODO is there a better way to convert this to an array? 120 Range[] ranges; 121 ranges.reserve(count); 122 for (auto iptr = 0u; iptr < count; iptr++) 123 { 124 ranges[iptr] = *(ptr + iptr); 125 } 126 return ranges; 127 } 128 129 /** 130 * Write a DOT graph describing the syntax tree to the given file. 131 */ 132 void print_dot_graph(File file) const 133 { 134 ts_tree_print_dot_graph(tstree, file.getFP); 135 } 136 137 /** 138 Get a DOT graph describing the syntax tree as a string 139 */ 140 auto dot_graph() const 141 { 142 import std.file : readText, tempDir; 143 import std.path : buildPath; 144 145 // TODO do we need to create a temp file? 146 const fileName = buildPath(tempDir(), "tree_sitter_dot_graph.txt"); 147 auto file = File(fileName, "w"); 148 print_dot_graph(file); 149 file.close(); 150 return readText(fileName); 151 } 152 }